package com.jkgh.remedium.rsgen.generator.java;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.PrintStream;

import com.jkgh.remedium.rsgen.vo.DataObject;
import com.jkgh.remedium.rsgen.vo.FieldInfo;

public class RemediumDataObjectJavaGenerator {

	public static void generate(File outputDir, DataObject d, String packageName) throws FileNotFoundException {

		File outFile = new File(outputDir, d.getClassName() + ".java");
		PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream(outFile)));

		out.println("package " + packageName + ";");
		out.println();
		out.println("import com.jkgh.asin.*;");
		out.println("import com.jkgh.asin.buffers.*;");
		out.println("import com.jkgh.remedium.*;");
		out.println("import com.jkgh.remedium.objects.*;");
		out.println("import com.jkgh.remedium.objects.messages.*;");
		out.println("import com.jkgh.remedium.states.*;");
		out.println("import com.jkgh.remedium.tools.*;");
		out.println();
		out.println("/**");
		out.println(" * " + d.getDescription());
		out.println(" * ");
		out.println(" * @author RS2JGenerator");
		out.println(" *");
		out.println(" */");
		out.println("public class " + d.getClassName() + " extends RemediumDataObject {");
		out.println();

		for (FieldInfo f : d.getFields()) {
			out.println("	/**");
			out.println("	 * " + f.getDescription());
			out.println("	 */");
			out.println("	public " + f.getClassName() + " " + f.getName() + ";");
			out.println();
		}

		out.println("	/**");
		out.println("	 * Default constructor.");
		out.println("	 */");
		out.println("	public " + d.getClassName() + "() {");
		out.println("	}");
		out.println();
		out.println("	/**");
		out.println("	 * Setting constructor.");
		out.println("	 * ");

		for (FieldInfo f : d.getFields()) {
			out.println("	 * @param " + f.getName() + " " + f.getDescription());
		}

		String fieldsList = "";
		for (FieldInfo f : d.getFields()) {
			fieldsList += f.getClassName() + " " + f.getName() + ", ";
		}
		fieldsList = fieldsList.substring(0, Math.max(0, fieldsList.length() - 2));

		out.println("	 */");
		out.println("	public " + d.getClassName() + "(" + fieldsList + ") {");
		for (FieldInfo f : d.getFields()) {
			out.println("		this." + f.getName() + " = " + f.getName() + ";");
		}
		out.println("	}");
		out.println();
		out.println("	// --------------------------------------------------------------------------------");
		out.println();
		out.println("	@Override");
		out.println("	public void produceContent(DataConsumer consumer, RemediumOutMessage message) {");
		for (FieldInfo f : d.getFields()) {
			out.println("		" + RemediumProducerJavaGenerator.generate(f.getClassName(), f.getName(), "message") + ";");
		}
		out.println("	}");
		out.println();
		out.println("	public static void consume(StateMachine machine, final RemediumInMessage message, final Future<" + d.getClassName() + "> future) {");
		out.println("		machine.setCurrentState(new GatheringState(machine, 1) {");
		out.println();
		out.println("			@Override");
		out.println("			protected void onNeededBytesAvailable() {");
		out.println("				switch (machine.produceByte()) {");
		out.println();
		out.println("				case RemediumConstants.NULL:");
		out.println("					future.goWith(null);");
		out.println("					break;");
		out.println();
		out.println("				case RemediumConstants.HISTORY:");
		out.println("					future.goWith((" + d.getClassName() + ") message.fromHistory(machine.produceInt()));");
		out.println("					break;");
		out.println();
		out.println("				case RemediumConstants.VALUE:");
		out.println("					consumeContent(machine, message, future);");
		out.println("					break;");
		out.println("				}");
		out.println("			}");
		out.println("		});");
		out.println("	}");
		out.println();
		out.println("	public static void consumeArray(final StateMachine machine, final RemediumInMessage message, final Future<" + d.getClassName() + "[]> future) {");
		out.println("		machine.setCurrentState(new GatheringState(machine, 4) {");
		out.println();
		out.println("			@Override");
		out.println("			protected void onNeededBytesAvailable() {");
		out.println("				final int length = machine.produceInt();");
		out.println("				if (length == -1) {");
		out.println("					future.goWith(null);");
		out.println("				} else if (length == 0) {");
		out.println("					future.goWith(new " + d.getClassName() + "[0]);");
		out.println("				} else {");
		out.println("					consume(machine, message, new Future<" + d.getClassName() + ">() {");
		out.println();
		out.println("						private int i = 0;");
		out.println("						private " + d.getClassName() + "[] result = new " + d.getClassName() + "[length];");
		out.println();
		out.println("						@Override");
		out.println("						public void goWith(" + d.getClassName() + " o) {");
		out.println("							result[i++] = o;");
		out.println("							if (i == length) {");
		out.println("								future.goWith(result);");
		out.println("							} else {");
		out.println("								consume(machine, message, this);");
		out.println("							}");
		out.println("						}");
		out.println("					});");
		out.println("				}");
		out.println("			}");
		out.println("		});");
		out.println("	}");
		out.println();
		out.println("	private static void consumeContent(final StateMachine machine, final RemediumInMessage message, final Future<" + d.getClassName() + "> future) {");
		out.println("		final " + d.getClassName() + " ret = new " + d.getClassName() + "();");
		out.println("		message.toHistory(ret);");
		RemediumConsumerJavaGenerator.generate(out, 2, d.getFields(), "future.goWith(ret);");
		out.println("	}");
		out.println("}");

		out.close();
	}
}
